#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include "../clsv/clsv.h"
#include "ntoh.h"
#include "hton.h"

/* client to server */
static int ntoh_clsv_login(void * p, void * stream);
static int ntoh_clsv_passwd(void * p, void * stream);
static int ntoh_clsv_get_ticket(void * p, void * stream);
static int ntoh_clsv_use_ticket(void * p, void * stream);
static int ntoh_clsv_upload(void * p, void * stream);
static int ntoh_clsv_list_categories(void * p, void * stream);
static int ntoh_clsv_list_users(void * p, void * stream);
static int ntoh_clsv_list_files(void * p, void * stream);

/* server to client */
static int ntoh_svcl_login(void * p, void * stream);
static int ntoh_svcl_passwd(void * p, void * stream);
static int ntoh_svcl_get_ticket(void * p, void * stream);
static int ntoh_svcl_upload(void * p, void * stream);

/* common packets */
static int ntoh_comm_data_block(void * p, void * stream);
static int ntoh_comm_list_block(void * p, void * stream);

static int (*ntoh_clsv[])(void * p, void * stream) =
{
	ntoh_clsv_login,			/* opcode = 0 */
	ntoh_clsv_passwd,			/* opcode = 1 */
	ntoh_clsv_get_ticket,		/* opcode = 2 */
	ntoh_clsv_use_ticket,		/* opcode = 3 */
	ntoh_clsv_upload,			/* opcode = 4 */
	ntoh_clsv_list_categories,	/* opcode = 5 */
	ntoh_clsv_list_users,		/* opcode = 6 */
	ntoh_clsv_list_files,		/* opcode = 7 */
	ntoh_comm_data_block,		/* opcode = 8 */
	ntoh_comm_list_block		/* opcode = 9 */
};

static int (*ntoh_svcl[])(void * p, void * stream) =
{
	ntoh_svcl_login,			/* opcode = 0 */
	ntoh_svcl_passwd,			/* opcode = 1 */
	ntoh_svcl_get_ticket,		/* opcode = 2 */
	ntoh_comm_data_block,		/* opcode = 3 use_ticket */
	ntoh_svcl_upload,			/* opcode = 4 */
	ntoh_comm_list_block,		/* opcode = 5 list_categories */
	ntoh_comm_list_block,		/* opcode = 6 list_users */
	ntoh_comm_list_block,		/* opcode = 7 list_files */
	ntoh_comm_data_block,		/* opcode = 8 data_block */
	ntoh_comm_list_block		/* opcode = 9 list_block */
};

int
ntoh_clsv_buffer(CLSV_BUFFER ** p, void * stream, int src)
{
	void * structure;
	OPC opcode;
	CLSV_BUFFER * auxP = *p;
	uint16_t aux;
	
	/* copy opcode from stream to struct, host byte order */
	memcpy((void *)&aux, stream, sizeof(aux));
	aux = ntohs(aux);
	auxP->opcode = aux;
	
	/* move pointer */
	structure = (void *)((char *)stream+sizeof(opcode));
	
	/* determine direction of transfer */
	switch (src)
	{
		case CL:
			if ((*ntoh_clsv[aux])((void *)&(auxP->data), structure) < 0)
			{
				fprintf(stderr, "Error passing from host to network\n");
				return -1;
			}
			break;
		case SV:
			if ((*ntoh_svcl[aux])((void *)&(auxP->data), structure) < 0)
			{
				fprintf(stderr, "Error passing from host to network\n");
				return -1;
			}
			break;
		default:
			fprintf(stderr, "Not called from server or client\n");
			return -1;
	}

	return 1;
}

static void
createstruct(char ** pointers, int * size, void * stream, int len)
{
	int i, bytes;
	char * offset;
	
	for (i=0, bytes=0; i<len; i++)
	{
		offset = (char *)stream + bytes;
		memcpy((void *)pointers[i], (void *)offset, size[i]);
		bytes += size[i];
	}
}

static int
ntoh_clsv_login(void * p, void * stream)
{
	CLSV_LOGIN * p2 = p;
	int ssize[] = {MAX_USER+1, MAX_EPASS};
	char * pointers[] = {p2->user, p2->pass};
	int len = sizeof(pointers)/sizeof(pointers[0]);

	createstruct(pointers, ssize, stream, len);
	return 1;
}

static int
ntoh_clsv_passwd(void * p, void * stream)
{
	CLSV_PASSWD * p2 = p;
	int ssize[] = {MAX_USER+1, MAX_EPASS, MAX_EPASS};
	char * pointers[] = {p2->user, p2->oldpass, p2->newpass};
	int len = sizeof(pointers)/sizeof(pointers[0]);
	
	createstruct(pointers, ssize, stream, len);
	return 1;
}

static int
ntoh_clsv_get_ticket(void * p, void * stream)
{
	CLSV_GET_TICKET * p2 = p;
	int ssize[] = {MAX_USER+1, MAX_EPASS, MAX_EFILENAME};
	char * pointers[] = {(char *) p2->user, (char *) p2->pass, 
							(char *)p2->filename};
	int len = sizeof(pointers)/sizeof(pointers[0]);
	
	createstruct(pointers, ssize, stream, len);
	return 1;
}


static int
ntoh_clsv_use_ticket(void * p, void * stream)
{
	CLSV_USE_TICKET * p2 = p;
	int ssize[] = {MAX_USER+1, MAX_EPASS, MAX_ETICKET};
	char * pointers[] = {p2->user, p2->pass, p2->ticket_id};
	int len = sizeof(pointers)/sizeof(pointers[0]);

	createstruct(pointers, ssize, stream, len);
	return 1;
}

static int
ntoh_clsv_upload(void * p, void * stream)
{
	CLSV_UPLOAD * p2 = p;
	int ssize[] = {sizeof(p2->size), MAX_FILENAME+1};
	char * pointers[] = {(char *) &(p2->size), p2->filename};
	int len = sizeof(pointers)/sizeof(pointers[0]);
	
	createstruct(pointers, ssize, stream, len);
	p2->size = ntohl(p2->size);
	return 1;
}

static int
ntoh_clsv_list_categories(void * p, void * stream)
{
	return 1;
}

static int
ntoh_clsv_list_users(void * p, void * stream)
{
	CLSV_LIST_USERS * p2 = p;
	
	int ssize[] = {MAX_USER+1, MAX_EPASS};
	char * pointers[] = {(char *)p2->user, (char *)p2->pass};
	int len = sizeof(pointers)/sizeof(pointers[0]);
	
	createstruct(pointers, ssize, stream, len);
	return 1;
}

static int
ntoh_clsv_list_files(void * p, void * stream)
{
	CLSV_LIST_FILES * p2 = p;
	int ssize[] = {MAX_USER+1, MAX_EPASS, MAX_CATEGORY+1};
	char * pointers[] = {(char *)p2->user, (char *)p2->pass, (char *) 
	p2->category};
	int len = sizeof(pointers)/sizeof(pointers[0]);
	
	createstruct(pointers, ssize, stream, len);
	return 1;
}

static int
ntoh_svcl_login(void * p, void * stream)
{
	SVCL_LOGIN * p2 = p;
	int ssize[] = {sizeof(p2->status)};
	char * pointers[] = {(char *)&(p2->status)};
	int len = sizeof(pointers)/sizeof(pointers[0]);
	
	createstruct(pointers, ssize, stream, len);
	p2->status = ntohs(p2->status);
	return 1;
}

static int
ntoh_svcl_passwd(void * p, void * stream)
{
	SVCL_PASSWD * p2 = p;
	int ssize[] = {sizeof(p2->status)};
	char * pointers[] = {(char *)&(p2->status)};
	int len = sizeof(pointers)/sizeof(pointers[0]);
	
	createstruct(pointers, ssize, stream, len);
	p2->status = ntohs(p2->status);
	return 1;
}

static int
ntoh_svcl_get_ticket(void * p, void * stream)
{
	SVCL_GET_TICKET * p2 = p;
	int ssize[] = {sizeof((p2->status)), sizeof(p2->dtime), sizeof(p2->etime),
				 	sizeof(p2->ftime), MAX_ETICKET};
	char * pointers[] = {(char *)&(p2->status), (char *)&(p2->dtime), (char *)
						&(p2->etime), (char *)&(p2->ftime), p2->id};
	int len = sizeof(pointers)/sizeof(pointers[0]);
	
	createstruct(pointers, ssize, stream, len);
	p2->status = ntohs(p2->status);
	p2->dtime = ntohl(p2->dtime);
	p2->etime = ntohl(p2->etime);
	p2->ftime = ntohl(p2->ftime);
	return 1;
}

static int
ntoh_svcl_upload(void * p, void * stream)
{
	SVCL_UPLOAD * p2 = p;
	int ssize[] = {sizeof(p2->status)};
	char * pointers[] = {(char *)&(p2->status)};
	int len = sizeof(pointers)/sizeof(pointers[0]);
	
	createstruct(pointers, ssize, stream, len);
	p2->status = ntohs(p2->status);
	return 1;
}

static int
ntoh_comm_data_block(void * p, void * stream)
{
	COMM_DATA_BLOCK * p2 = p;
	int ssize[] = {sizeof(p2->status), MAX_DATA};
	char * pointers[] = {(char *)&(p2->status), p2->data};
	int len = sizeof(pointers)/sizeof(pointers[0]);
	
	createstruct(pointers, ssize, stream, len);
	
	p2->status = ntohs(p2->status);
	return 1;
}

static int
ntoh_comm_list_block(void * p, void * stream)
{
	COMM_LIST_BLOCK * p2 = p;
	int ssize[] = {sizeof(p2->status), MAX_LIST};
	char *pointers[] = {(char *)&(p2->status), (char *)p2->data};
	int len = sizeof(pointers)/sizeof(pointers[0]);
	
	createstruct(pointers, ssize, stream, len);
	p2->status = ntohs(p2->status);
	return 1;
}

